package com.http;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.net.ssl.SSLContext;

import org.apache.http.Header;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPatch;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;


public abstract class BasicClient {

	private static CloseableHttpClient httpClient;
	
	/**
     * 信任SSL证书
     */
    static {
        try {
            @SuppressWarnings("deprecation")
			SSLContext sslContext = SSLContextBuilder.create().useProtocol(SSLConnectionSocketFactory.SSL).loadTrustMaterial((x, y) -> true).build();
            RequestConfig config = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(5000).build();
            httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).setSSLContext(sslContext).setSSLHostnameVerifier((x, y) -> true).build();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
	
	public HttpResponse post(String url, Map<String, String> headers, List<NameValuePair> body) throws Exception {
		HttpPost httpReqeust = new HttpPost(url);
		return this.execute(httpReqeust, headers, body);
	}

	public HttpResponse put(String url, Map<String, String> headers, List<NameValuePair> body) throws Exception {
		HttpPut httpReqeust = new HttpPut(url);
		return this.execute(httpReqeust, headers, body);
	}

	public HttpResponse delete(String url, Map<String, String> headers) throws Exception {
		HttpDelete httpReqeust = new HttpDelete(url);
		return this.execute(httpReqeust, headers, null);
	}

	public HttpResponse get(String url, Map<String, String> headers) throws Exception {
		HttpGet httpReqeust = new HttpGet(url);
		return this.execute(httpReqeust, headers, null);
	}

    public HttpResponse patch(String url, Map<String, String> headers, List<NameValuePair> body) throws Exception {
    		HttpPatch httpReqeust = new HttpPatch(url);
    		return this.execute(httpReqeust, headers, body);
	}

	private HttpResponse execute(HttpRequestBase httpRequest, Map<String, String> headers, List<NameValuePair> body)
			throws Exception {
		HttpResponse res = new HttpResponse();
		try {
			if (headers != null) {
				for (Map.Entry<String, String> m : headers.entrySet()) {
					httpRequest.setHeader(m.getKey(), m.getValue());
				}
			}
			if (headers == null || !headers.containsKey("Content-Type")) {
				httpRequest.setHeader("Content-Type", ContentType.APPLICATION_FORM_URLENCODED.getMimeType());
			}

			RequestConfig.Builder resourceConfig = RequestConfig.custom();
			resourceConfig.setConnectTimeout(60000)
				.setConnectionRequestTimeout(60000)
				.setSocketTimeout(60000);
			httpRequest.setConfig(resourceConfig.build());

			if (body != null) {
				((HttpEntityEnclosingRequestBase)httpRequest).setEntity(new UrlEncodedFormEntity(body, "UTF-8"));
				System.out.println(EntityUtils.toString(((HttpEntityEnclosingRequestBase)httpRequest).getEntity(), "UTF-8"));
			}
			CloseableHttpResponse response = httpClient.execute(httpRequest);
			String responseBody = EntityUtils.toString(response.getEntity(), "UTF-8");
			Header[] responseHeaders = response.getAllHeaders();
			Map<String,List<String>> resHeaderMap = new HashMap<String,List<String>>();
			for (Header resHeader : responseHeaders) {
				List<String> headerValList = new ArrayList<String>();
				headerValList.add(resHeader.getValue());
				resHeaderMap.putIfAbsent(resHeader.getName(), headerValList);
			}
			int responseCode = response.getStatusLine().getStatusCode();
			
			res.setStatusCode(responseCode);
			res.setBody(responseBody);
			res.setHeaders(resHeaderMap);
		} finally {
			if (httpClient != null) {
				httpClient.close();
			}
		}
		return res;
	}
}
